/*--------------------------- MegaWave2 Module -----------------------------*/
/* mwcommand
  name = {eye_fextract};
  version = {"2.0"};
  author = {"Baptiste Coulange"};
  function = {"fExtract with an user friendly interface (eye) :\n
				clic to extract the part"};
  usage = {
  	 'z':[zoom=1.0]->zoom  "Zoom factor",	
     'o':[order=0]->order  "Zoom order: 0,1=linear,-3=cubic,3,5..11=spline",
	 'f'->f				"extrait l'image avec des cotés une puissance de deux minimale qui entoure la zone choisie",
     'F'->F				"déformation de l'image par zéro padding pour obtenir des cotes etant des puissances de 2",
	 'p'->p				"Extraction d'un parallelogramme",
	 in->in            "input Fimage",
     out<-out           "output Fimage",
	 'W'->W				"return the extraction window (with -p)",
  notused->window       "Window to view the image (internal use)"
          };
*/
/*----------------------------------------------------------------------
02/09 : added 'F' option (B. Coulange)
----------------------------------------------------------------------*/


#include <stdio.h>
#include "mw.h"
#include <math.h>
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)>(y)?(y):(x))
#define MMIN(x,y,a,b) MIN(MIN(x,y),MIN(a,b))
#define MMAX(x,y,a,b) MAX(MAX(x,y),MAX(a,b))

/* Include the window since we use windows facility */
#include "window.h"

extern Cimage clocal_zoom();
extern Fimage flocal_zoom();
extern void fzoom();
extern fftzoom2();
extern fextractParall();

static Wframe *PlotWindow=NULL;  

/* Param structure used to send parameters to fview_notify() */

typedef struct fextract_SParam {
  Fimage image_in;
  Cimage image_work;	
  Fimage image_out;  
  int Pos1x,Pos1y,Pos2x,Pos2y;
  char *f,*F,*p,*W;
} *fextract_Param;

int nextPow2(a)
	int a;
	{
	int out;
	out=1;	
	while(out<=a){
		out=out*2;
	}
	return out;
	}

int precPow2(a)
	int a;
	{
	int out;
	out=nextPow2(a);	
	while(out>a){
		out=out/2;
	}
	return out;
	}



int oldx1,oldy1,oldevent,cscale_shown;
float zfactor;

void fextract_notify_help()

{
  printf("\n\t\tHelp on line\n");

  printf("\nMouse:\n");
  printf("\tLeft button: choose points of extraction.\n");


  printf("\nKeyboard:\n");
  printf("\tQ: Quit.\n");
  printf("\tH: Help.\n");

}

/*     A notify function must return a value ....      */
/*       0 if there was no event catched               */
/*     > 0 if there was an event catched (but Destroy) */
/*      -1 if the event Destroy was catched (or 'Q')   */

int fextract_notify(ImageWindow,param)

Wframe *ImageWindow;
void *param;          /* Users's parameters: don't forget the cast ! */

{
  int x1,y1,wz,event,button_mask,ret,c,bgx,bgy;
  char mess[80];
  float ng;
  fextract_Param images;
  Cimage image;
  Fimage fimage;
	
  images = (fextract_Param) param;  /* Cast */	
  image = images->image_work;
  fimage= images->image_in;
	
  event = WUserEvent(ImageWindow); /* User's event on ImageWindow */	
  if (event < 0) ret=1; else ret=event;
	
  if (event != W_DESTROY)
     {
       WGetStateMouse(ImageWindow,&x1,&y1,&button_mask);	
	 }

/* Draw seleciton square */
  if (!(images->p)) {
		if (images->Pos1x!=-1) {

	      WSetTypePencil(W_COPY);
	      WSetSpecialColorPencil(ImageWindow);
	      if (WLoadBitMapImage(ImageWindow,image->gray,image->ncol,
				   image->nrow)!= 0) return(-1);
	      WRestoreImageWindow(ImageWindow,0,0,image->ncol,image->nrow); 
	      WDrawLine(ImageWindow,images->Pos1x,images->Pos1y,images->Pos1x,y1);  
	      WDrawLine(ImageWindow,images->Pos1x,images->Pos1y,x1,images->Pos1y);  
	      WDrawLine(ImageWindow,x1,images->Pos1y,x1,y1);  
	      WDrawLine(ImageWindow,images->Pos1x,y1,x1,y1);  
	  	  WFlushWindow(ImageWindow);	  
	      cscale_shown = 0;
  			}
  } else { if(images->Pos2x!=-1){
	  	  bgx=images->Pos1x+x1-images->Pos2x;
		  bgy=images->Pos1y+y1-images->Pos2y;	
	      WSetTypePencil(W_COPY);
	      WSetSpecialColorPencil(ImageWindow);
	      if (WLoadBitMapImage(ImageWindow,image->gray,image->ncol,
				   image->nrow)!= 0) return(-1);
	      WRestoreImageWindow(ImageWindow,0,0,image->ncol,image->nrow); 
	 	  WDrawLine(ImageWindow,images->Pos1x,images->Pos1y,images->Pos2x,images->Pos2y);
	 	  WDrawLine(ImageWindow,images->Pos1x,images->Pos1y,bgx,bgy);	  
	      WDrawLine(ImageWindow,images->Pos2x,images->Pos2y,x1,y1);
	      WDrawLine(ImageWindow,bgx,bgy,x1,y1);	  
  			  	  WFlushWindow(ImageWindow);	  
	      cscale_shown = 0;
  		} else { 
				   if(images->Pos1x!=-1){
		WSetTypePencil(W_COPY);
	    WSetSpecialColorPencil(ImageWindow);
	    if (WLoadBitMapImage(ImageWindow,image->gray,image->ncol,
				   image->nrow)!= 0) return(-1);
	    WRestoreImageWindow(ImageWindow,0,0,image->ncol,image->nrow); 
	    WDrawLine(ImageWindow,images->Pos1x,images->Pos1y,x1,y1);  			   
		WFlushWindow(ImageWindow);	  
	    cscale_shown = 0;
				   }
			  }
  }
					   
  switch(event)
    {mage->ncol+i;
      							pos2 = (j-images->Pos1y)*(tmp->ncol)+(i-images->Pos1x);
      					
								
								if (j-(images->Pos1y)>=0 && j-images->Pos1y<(tmp->nrow) && 
	  							i-images->Pos1x>=0 && i-images->Pos1x<(tmp->ncol) &&
	 				 			i>=0 && i<fimage->ncol && j>=0 && j<fimage->nrow) {
								tmp->gray[pos2] = fimage->gray[pos1];}  
    							}
						float zfactorx,zfactory;
						zfactorx=(float)precPow2(tailx)/((float)tailx);	
						zfactory=(float)precPow2(taily)/((float)taily);					
						images->image_out=mw_change_fimage(images->image_out,precPow2(taily),precPow2(tailx));
						fftzoom2(tmp,images->image_out,&zfactorx,&zfactory,NULL);
						} else {
					
							if(images->f){
							int desTailx,desTaily,enPlusx,enPlusy;
							desTailx=nextPow2(tailx);
							desTaily=nextPow2(taily);
							enPlusx=desTailx-tailx;
							enPlusy=desTaily-taily;
					
								if(desTailx<=fimage->ncol&&desTaily<=fimage->nrow) {
								tailx=desTailx;
								taily=desTaily;

						
									if((images->Pos1x-enPlusx/2>=0)&&(x1+(enPlusx-enPlusx/2)<fimage->ncol)){
									images->Pos1x=images->Pos1x-enPlusx/2;
									x1=x1+(enPlusx-enPlusx/2);
									} else {
									int nouvDep;
									nouvDep=x1-desTailx;
									while(nouvDep<0){
									nouvDep=nouvDep+1;	
									}
									images->Pos1x=nouvDep;
									x1=nouvDep+desTailx;
									}
						
									if((images->Pos1y-enPlusy/2>=0)&&(y1+(enPlusy-enPlusy/2)<fimage->ncol)){
									images->Pos1y=images->Pos1y-enPlusy/2;
									y1=y1+(enPlusy-enPlusy/2);
									} else {
									int nouvDep;
									nouvDep=y1-desTaily;
									while(nouvDep<0){
									nouvDep=nouvDep+1;
									}
									images->Pos1y=nouvDep;
									y1=nouvDep+desTaily;
									}

								} else {
								printf("Ce type de redimensionnement est impossible -> option 'f' ignorée\n");
								}
					
							}
					
			 			images->image_out = mw_change_fimage(images->image_out,taily,tailx);	
				
				
					
						int i,j,pos1,pos2;
						for (i=images->Pos1x;i<=x1;i++)
   		 					for (j=images->Pos1y;j<=y1;j++) {
      						pos1 = j*fimage->ncol+i;
      						pos2 = (j-images->Pos1y)*(images->image_out->ncol)+(i-images->Pos1x);
      					
								
							if (j-(images->Pos1y)>=0 && j-images->Pos1y<(images->image_out->nrow) && 
	  						i-images->Pos1x>=0 && i-images->Pos1x<(images->image_out->ncol) &&
	 				 		i>=0 && i<fimage->ncol && j>=0 && j<fimage->nrow) {
							images->image_out->gray[pos2] = fimage->gray[pos1];}  
    						}   
					
					
					}
				ret=-1;
				}
			}
		}
	  break;
	case  W_KEYPRESS:
	 c = WGetKeyboard();
      switch(c)
	{
	  case 'h': case 'H': fextract_notify_help();
	  break;	
	case 'q':
		ret=-1;
			break;
			
	}
	}

  return(ret);
}

/* tool modules */

Cimage fimage_to_cimage(in,out)
     Fimage in;
     Cimage out;
{
  int n;
  float v;

  out = mw_change_cimage(out,in->nrow,in->ncol);
  for (n=in->nrow*in->ncol;n--;) {
    v = in->gray[n];
    if (v<0.) v=0.;
    if (v>255.) v=255.;
    out->gray[n] = (unsigned char)v;
  }

  return(out);
}



/* Main loop */

Fimage eye_fextract(in,out,zoom,window,order,f,F,p,W)
	Fimage in,out;
    char   *window;
	float *zoom;
	int *order;
	char *f,*F,*p,*W;
{
	int x0,y0;
	x0=50;
	y0=50;
    Wframe *ImageWindow;
    Fimage tmp;
	Cimage cimage;
	mw_change_fimage(out,0,0);
	float inverse_zoom;
	tmp = mw_new_fimage();
  if (*zoom != 1.0) 
    {
      tmp = mw_change_fimage(NULL,0,0);
      if (tmp == NULL) mwerror(FATAL,1,"Not enough memory\n");
      if (*zoom>1.0) 
	fzoom(in,tmp,NULL,NULL,zoom,order,NULL,NULL);
      else {
	inverse_zoom = 1./(*zoom);
	fzoom(in,tmp,NULL,NULL,&inverse_zoom,order,NULL,(char *)1);
      }
      sprintf(tmp->name,"%s %.1fX",in->name,*zoom);
    }
  else {
	  tmp=mw_change_fimage(tmp,in->nrow,in->ncol);
      mw_copy_fimage(in,tmp);
  }
	
    fthre(tmp,tmp,NULL,(char *)1,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
  	cimage = fimage_to_cimage(tmp,NULL);
	
	fextract_Param param;
    ImageWindow = (Wframe *)
    mw_get_window((Wframe *) window,cimage->ncol,cimage->nrow,x0,y0,in->name);
	if (ImageWindow == NULL)
    mwerror(INTERNAL,1,"NULL window returned by mw_get_window\n");
  	mw_delete_fimage(tmp);	
	

	
	WLoadBitMapImage(ImageWindow,cimage->gray,cimage->ncol,cimage->nrow); 
  	WRestoreImageWindow(ImageWindow,0,0,cimage->ncol,cimage->nrow); 
  	WFlushWindow(ImageWindow);
	oldx1 = oldy1 = oldevent = -1;
    zfactor = *zoom;
	

	cscale_shown = 0;

	param = (fextract_Param) malloc(sizeof(struct fextract_SParam));
    if (param == NULL) mwerror(FATAL,1,"not enough memory\n");
	
	WSetUserEvent(ImageWindow,W_MS_BUTTON | W_KEYPRESS);

	param->image_in=mw_change_fimage(NULL,in->nrow,in->ncol);
	mw_copy_fimage(in,param->image_in);
	param->image_in=in;
	param->image_work=cimage;	
	param->image_out=out;
	param->Pos1x=-1;
	param->Pos1y=-1;
	param->Pos2x=-1;
	param->Pos2y=-1;
	param->p=p;
	param->f=f;
	param->F=F;
	param->W=W;
	mw_window_notify(ImageWindow,(void *)param,fextract_notify);
    mw_window_main_loop();

}
